【netaddr系列】用python助力你处理网段

您所在的位置:网站首页 python ip地址异常判定 【netaddr系列】用python助力你处理网段

【netaddr系列】用python助力你处理网段

2023-05-11 19:54| 来源: 网络整理| 查看: 265

【netaddr系列】用python助力你处理网段

上一节分享中我们简单介绍了netaddr,以及如何在netaddr中定义操作一个IP地址。

本节分享,我们将来介绍netaddr的IPNetwork这个类,它是对网络地址段的定义和操作的一个工具类。可以以非常灵活的方式定义网段,获取网段的一些常用信息,同时可以和网络地址与网段进行一些包含关系的运算。

话不多说,咱们马上开始。

netaddr中的IPNetwork

IPNetwork objects are used to represent subnets, networks or VLANs that accept CIDR prefixes and netmasks.

IPNetwork对象用来表示子网、网络以及CIDR格式、普通掩码格式的VLAN。

IPNetwork的定义网段的几种方式

它支持的种类非常多,比如192.168.1.1/24这种格式,192.168.1.0/24也可以,192.168.1.0/255.255.255.0也支持,ACL中的反掩码也ok。一接下来我们一个个过一下

无掩码信息或者网段信息,使用默认的32位掩码from netaddr import IPNetwork if __name__ == '__main__': # IP v4 network ip_network = IPNetwork('192.168.1.1') # 默认掩码255.255.255.255或者是32 print(ip_network) # __str__方法返回的是字符串表达形式 cidr的表达方式 print(repr(ip_network)) # __repr__方法是类名称内包裹cidr的表达方式

【netaddr系列】用python助力你处理网段_IP

image-20210316062806835

掩码表达方式cidr的prefix方式

个人而言,用cidr前缀的掩码表示方式,更加简短直观,

ip_network = IPNetwork('192.1.0.29/25') print(ip_network) # __str__方法返回的是字符串表达形式 cidr的表达方式 print(repr(ip_network)) # __repr__方法是类名称内包裹cidr的表达方式

【netaddr系列】用python助力你处理网段_字符串_02

image-20210316064757135

netmask方式

在一些网络配置上,我们看到的这种点分十进制的netmask表示方法比较多,netaddr是兼容这种表达方式的,但netaddr也是在底层使用cidr的prefix掩码表达方式进行了统一。

# IP v4 network with netmask ip_network = IPNetwork('192.168.1.0/255.255.255.0') print(ip_network) # __str__方法返回的是字符串表达形式 cidr的表达方式 print(repr(ip_network)) # __repr__方法是类名称内包裹cidr的表达方式

【netaddr系列】用python助力你处理网段_IP_03

image-20210316064656063

关于主机位

在python的ipaddress中192.168.1.1/24定义一个IP netwrok是会报错的,因为这实际上是一个网络接口的定义方式,换句话说这个IP network不纯粹,它包含了主机位。但是在netaddr中,这种表示方式是合法的,它兼容了严格的网络地址段的定义,和这种包含了主机位的网段的定义。

netaddr在底层记录了那些核心的信息

实际上它存储了三种信息:

IP 地址,存储的是一个整数,有无主机位均可IP的版本,v4还是v6the CIDR prefix bitmask,一个CIDR表示方法下的前缀掩码

在获取网段信息的时候,对于1而言,是一个严格的网段和一个网络接口上的地址都是可以接受的,因为后续的信息足够还原一个网段,同时它还能保留主机位信息,这个我们要和python自带的ipadress区别开,也要和IPy的网段定义区别开。ipaddress有专门的ip interface的类来表示此类信息

所以在做一些IP地址规划的时候,如果要严格起来,有两种方案:

用IPy或者ipadress里的IPNetwork对应的对象类,如果报错,说明这个网段不纯粹,包含主机位。用netaddr,然后取出网络位和掩码位,网络位与当时初始化的IP地址比较,相同,则是严格的网段。

我们再举个例子

这个IP段中没有主机位

# IP v4 network with cidr prefix netmask ip_network = IPNetwork('192.1.0.29/25') print(ip_network) # __str__方法返回的是字符串表达形式 cidr的表达方式 print(repr(ip_network)) # __repr__方法是类名称内包裹cidr的表达方式 print(repr(ip_network.network)) #网络位,会根据IP地址和掩码计算出网络位 print(repr(ip_network.netmask)) # 返回一个掩码是IPAdress类,如果想用字符串,必须强制转str,或者是所在的函数比如format会自动调用__str__方法 print(repr(ip_network.prefixlen),type(repr(ip_network.prefixlen))) # 返回的掩码的字符串 print(repr(ip_network.ip)) # 返回的是我们传入的主机位

【netaddr系列】用python助力你处理网段_字符串_04

image-20210320091502370

执行结果

【netaddr系列】用python助力你处理网段_ci_05

image-20210320091545963

我们换一个带主机位的地址去试试

# IP v4 network with cidr prefix netmask ip_network = IPNetwork('192.1.0.29/25') print(ip_network) # __str__方法返回的是字符串表达形式 cidr的表达方式 print(repr(ip_network)) # __repr__方法是类名称内包裹cidr的表达方式 print(repr(ip_network.network)) #网络位,会根据IP地址和掩码计算出网络位 print(repr(ip_network.netmask)) # 返回一个掩码是IPAdress类,如果想用字符串,必须强制转str,或者是所在的函数比如format会自动调用__str__方法 print(repr(ip_network.prefixlen),type(repr(ip_network.prefixlen))) # 返回的掩码的字符串 print(repr(ip_network.ip)) # 返回的是我们传入的主机位

【netaddr系列】用python助力你处理网段_字符串_06

image-20210320091346356

执行结果

【netaddr系列】用python助力你处理网段_IP_07

image-20210320091408674

当然,我们有办法规避这个问题,IPNetwork在初始化的时候有一个参数,是flags,意思是如何计算它的主机位,有一种方式是NOHOST,就是去除主机位

我们在开始的时候引入from netaddr.core import N,NOHOST这两个是等价的

然后调用的时候

# IP v4 network with cidr prefix netmask ip_network = IPNetwork('192.1.0.29/25',flags=N) print(ip_network) # __str__方法返回的是字符串表达形式 cidr的表达方式 print(repr(ip_network)) # __repr__方法是类名称内包裹cidr的表达方式 print(repr(ip_network.network)) #网络位,会根据IP地址和掩码计算出网络位 print(repr(ip_network.netmask)) # 返回一个掩码是IPAdress类,如果想用字符串,必须强制转str,或者是所在的函数比如format会自动调用__str__方法 print(repr(ip_network.prefixlen),type(repr(ip_network.prefixlen))) # 返回的掩码的字符串 print(repr(ip_network.ip)) # 返回的是我们传入的主机位

【netaddr系列】用python助力你处理网段_IP_08

image-20210320091847044

运行一下看结果

【netaddr系列】用python助力你处理网段_IP_09

image-20210320091903648

目前为止,我没有找到一种比较严格的方式,在这个网段中包含主机位的时候报出错来。所以在我们自己设计IPAM的时候,我相关环节用的还是ipadress和IPy相关对象。如果大家没有这种场景,便可以忽略,或者自己写个函数,判断一下都可以。这种方式表示一些3层接口等的时候还是比较方便的

其他几种表示方式

【netaddr系列】用python助力你处理网段_IP_10

image-20210320094305142

支持反掩码,支持简写。

IPNetwork的几个重要属性

IPNetwork的几个重要属性,我们刚才有讲过

现在从头给大家捋捋,我能想到的,或者用过的

from netaddr import IPNetwork if __name__ == '__main__': ip_network = IPNetwork('192.1.0.0/24') print(ip_network) # __str__方法返回的是字符串表达形式 cidr的表达方式 print(repr(ip_network)) # __repr__方法是类名称内包裹cidr的表达方式 print(repr(ip_network.network)) #网络位,会根据IP地址和掩码计算出网络位 print(repr(ip_network.netmask)) # 返回一个掩码是IPAdress类,如果想用字符串,必须强制转str,或者是所在的函数比如format会自动调用__str__方法 print(repr(ip_network.prefixlen),type(repr(ip_network.prefixlen))) # 返回的掩码的字符串 print(repr(ip_network.ip)) # 返回的是我们传入的主机位 print(ip_network.first) # 取第一个地址的整数形式 print(ip_network.last) # 取最后一个地址的整数形式,这两个如果放到数据库里用数字比较,计算归属非常快 print(ip_network.cidr, type(ip_network.cidr)) # cidr字符互形式

【netaddr系列】用python助力你处理网段_IP_11

image-20210320094129959

结果

【netaddr系列】用python助力你处理网段_ci_12

image-20210320094155052

判断IP地址或者网段之间的归属关系

其实非常简单,用in操作即可

网段、IP 可以和网段进行一个in操作来判断前者是否归属于后者或者简单点,IP地址直接来初始化IPNetwork也行(毕竟会自动掩32位,就是一个IP地址)。

【netaddr系列】用python助力你处理网段_字符串_13

image-20210320095033646

结果

【netaddr系列】用python助力你处理网段_ci_14

image-20210320095055170

我们换一个IP地址试试

【netaddr系列】用python助力你处理网段_ci_15

image-20210320095117079

结果

【netaddr系列】用python助力你处理网段_IP_16

image-20210320095129088

第一个IPNetwork换成IPAdress去初始化判断也是没问题的。

【netaddr系列】用python助力你处理网段_IP_17

image-20210320095325499

以上再进行HW的时候,经常来判断一个地址是否命中某策略(一个地址段),或者判断属于哪个Vlan,属于哪个地址规划(前提是你手头有地址规划),非常适合使用。相关的规划或者归属,可以从某些平台的API导出,或者是从设备上采集解析出来后保存。

之前咱们也聊过,用IP地址的int方式来和网段的起止int形式比较,会特别快,大家也可以自己试试,如果有DB,就不用for循环了,或者自己办法用一些特殊的包和对象来进行这个比较过程。

总结

今天简单的和大家简介了IPNetwork的使用,也是简单的讲讲,最后讲到了地址的归属和网段的包含关系,后续还有很多,比如网段的划分和合并,或者一些连续网段的操作等等。且等下期,今天就分享到这里。

限于本人的网络水平有限,有一些专业术语可能表述有误,欢迎大家斧正。但整体使用阅读应该是没什么问题的。

最后

同名知乎专栏和微信公众号:NetDevOps加油站,欢迎你的加入!

【netaddr系列】用python助力你处理网段_IP_18

image-20201219222006955



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3